#include "AOMaterial.h"
#include "Integrator.h"

AOMaterial::AOMaterial(Double minDistance, Double maxDistance, Float strength, int sampleCount) :
	minDistance(minDistance), maxDistance(maxDistance), sampleCount(sampleCount) {
	setStrength(strength);
}

AOMaterial::AOMaterial(shared_ptr<Material> material, Double minDistance, Double maxDistance, Float strength, int sampleCount) :
	material(material), minDistance(minDistance), maxDistance(maxDistance), sampleCount(sampleCount) {
	setStrength(strength);
}

void AOMaterial::setDistance(Double minDistance, Double maxDistance) {
	this->minDistance = minDistance;
	this->maxDistance = maxDistance;
}

void AOMaterial::setSampleCount(int sampleCount) {
	this->sampleCount = sampleCount;
}

void AOMaterial::setSelfShadowingOnly(bool value) {
	selfShadowingOnly = value;
}

Color AOMaterial::shade(const Scene * scene, const Ray & ray, const IntersectResult & intersect, const TraceState & traceState) const {
	Color color = Colors::White;
	Float hitRate = 0;
	Ray AORay(intersect.position);
	if (selfShadowingOnly) {
		IntersectResult result;
		for (int i = 0; i < sampleCount; i++) {
			AORay.dir = cosWeightedRandomHemisphereDirection(intersect.normal);
			if (intersect.primitive->intersect(AORay, result)) {
				if (isInRange(result.distance, minDistance, maxDistance))
					hitRate++;
			}
		}
	} else {
		for (int i = 0; i < sampleCount; i++) {
			AORay.dir = cosWeightedRandomHemisphereDirection(intersect.normal);
			if (scene->intersectP(AORay, minDistance, maxDistance))
				hitRate++;
		}
	}
	color *= strength * (1 - hitRate / sampleCount);
	return material ? color *= material->shade(scene, ray, intersect, traceState) : color;
}